package excelgo

import (
	"fmt"
	"io"
	"reflect"
	"strings"
	"time"

	ex "github.com/douyacun/go-struct-excel"
	"github.com/xuri/excelize/v2"
)

// excel文件解析函数
// 关键是泛型和参数，泛型是excel中二维表对应的结构体，结构体字段全为string类型
// reader是excel文件的文件流
// sheet为工作簿名称，指定读取那个工作簿
// 返回值是以T为类型的结构体体数组
func ParseExcel[T any](reader io.Reader, sheet string) ([]T, error) {
	f, err := excelize.OpenReader(reader)
	if err != nil {
		fmt.Println(err)
	}
	defer func() {
		if err := f.Close(); err != nil {
			fmt.Println(err)
		}
	}()
	// 获取sheet所有行
	rows, err := f.GetRows(sheet)
	if err != nil {
		fmt.Println("ParseExcel err:", err)
		return nil, err
	}

	var result = make([]T, 0)
	// _是索引号，从0开始，row是整行数据
	for i, row := range rows {
		if i == 0 {
			continue
		}
		//for _, colCell := range row {
		//
		//}
		array := GenValByArray[T](row)
		result = append(result, array)
	}
	return result, nil
}

// 导出为excel文件流
// T为任意了类型
// data参数为T类型的指针数组，必须是指针数组
// name为导出的文件名
func Export[T any](data []T, name string, sheetName string) ([]byte, error) {
	if name == "" {
		name = "file.xlsx"
	}
	if !strings.Contains(name, ".xlsx") {
		name = name + ".xlsx"
	}
	excel := ex.NewExcel(name)
	defer excel.File.Close()
	sheet, err := excel.AddSheet(sheetName)
	if err != nil {
		return nil, err
	}
	if err = sheet.AddData(data); err != nil {
		return nil, err
	}
	return excel.Bytes()
}

// 字符串数组生成结构体
// 字符串数组的顺序要和泛型的结构体字段顺序一致，从而依次赋值
func GenValByArray[T any](p []string) T {
	var param T
	info := ReflectInfo(param)
	structType := reflect.TypeOf(param)
	// 使用反射创建结构体实例
	structValue := reflect.New(structType).Elem()
	for i, model := range info {
		// 设置结构体字段的值
		field1 := structValue.FieldByName(model.Name)
		if field1.IsValid() && field1.CanSet() {
			if model.TypeName == "time.Time" {
				// 判断是日期还是时间
				// 注意时间的格式只支持`2024-10-10` 和`2024-10-10 12:30:00`两种。
				if len(p[i]) == 10 {
					field1.Set(reflect.ValueOf(dateStandardStr(p[i])))
				} else if len(p[i]) == 19 {
					field1.Set(reflect.ValueOf(strStandardTime(p[i])))
				} else {
					field1.Set(reflect.ValueOf(strStandardTime("")))
				}
			} else if model.TypeName == "int" {
				field1.Set(reflect.ValueOf(strInt(p[i])))
			} else if model.TypeName == "int32" {
				field1.Set(reflect.ValueOf(strInt32(p[i])))
			} else if model.TypeName == "float32" || model.TypeName == "float64" {
				field1.Set(reflect.ValueOf(strFloat64(p[i])))
			} else if model.TypeName == "bool" {
				field1.Set(reflect.ValueOf(strBool(p[i])))
			} else {
				field1.Set(reflect.ValueOf(p[i]))
			}
		}
	}
	return structValue.Interface().(T)
}

// 反射返回结构体的字段名称，字段类型和字段的值，以数组形式返回
// 泛型T为结构体类型，参数model为泛型结构体实例
// 返回值为字段信息的数组
func ReflectInfo[T any](model T) []ReflectModel {
	var result = make([]ReflectModel, 0)
	getType := reflect.TypeOf(model)
	for i := 0; i < getType.NumField(); i++ {
		fieldType := getType.Field(i)
		name := fieldType.Name
		typeName := fieldType.Type.String()
		value := reflect.ValueOf(model).Field(i)
		if typeName == "time.Time" {
			result = append(result, ReflectModel{name, typeName, timeStandardStr(time.Now())})
		} else {
			result = append(result, ReflectModel{name, typeName, value.Interface()})
		}
	}
	return result
}
